package com.pap.spidemo.factorybean;

import com.pap.obj.vo.logineduser.LoginedUserVO;
import com.pap.spidemo.exception.NoSPIInterfaceServerException;
import com.pap.spidemo.interfaces.ISPIInterface;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 *  代理类主要目的就是在具体调用执行时，根据传入的参数来选中具体的执行者，执行后并返回对应的结果
 * @param <T>
 */
public class SPIInterfaceFactoryBean<T> implements FactoryBean<T> {
    private Class<? extends ISPIInterface> spiClz;

    private List<ISPIInterface> spiInterfaceListlist;

    public SPIInterfaceFactoryBean(ApplicationContext applicationContext, Class<? extends ISPIInterface> clz) {
        this.spiClz = clz;
        // 获取所有的SPI实现类
        Map<String, ? extends ISPIInterface> map = applicationContext.getBeansOfType(spiClz);
        spiInterfaceListlist = new ArrayList<>(map.values());
        spiInterfaceListlist.sort(Comparator.comparingInt(ISPIInterface::order));
    }

    @Override
    @SuppressWarnings("unchecked")
    public T getObject() throws Exception {
        // jdk动态代理类生成
        // 通过jdk生成代理类，代理类中，遍历所有的SPI实现，根据传入的第一个参数作为条件进行匹配，找出首个命中的SPI实现类
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                for (ISPIInterface spi : spiInterfaceListlist) {
                    for(int i = 0; i < args.length ; i++) {
                        if(args[i] instanceof LoginedUserVO) {
                            if (spi.conditionVerify((LoginedUserVO)args[i])) {
                                // 第一个参数作为条件选择
                                return method.invoke(spi, args);
                            }
                        }
                    }
                }

                throw new NoSPIInterfaceServerException("NO SPI INTERFACE SERVER CAN EXECUTE! spiInterfaceListlist: " + spiInterfaceListlist);
            }
        };

        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{spiClz},
                invocationHandler);
    }

    @Override
    public Class<?> getObjectType() {
        return spiClz;
    }
}